# -*- mode: Perl -*-
# /=====================================================================\ #
# |  cleveref                                                           | #
# | Implementation for LaTeXML                                          | #
# |=====================================================================| #
# | Part of LaTeXML:                                                    | #
# |  Public domain software, produced as part of work done by the       | #
# |  United States Government & not subject to copyright in the US.     | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
# \=========================================================ooo==U==ooo=/ #
package LaTeXML::Package::Pool;
use strict;
use warnings;
use LaTeXML::Package;

# Should just work? Nope.
# But we do need to read it in to get access to all the language dependent stuff!
# We won't yet support the optional arg to the redefined \label...
Let(T_CS('\lx@cleverref@save@label'), T_CS('\label'));
DefMacro('\lx@cleverref@label[]', '\lx@cleverref@save@label');
my $amswasloaded = LookupValue('amsmath.sty_loaded');
# Pretend amsmath already loaded (if it will be), to avoid pointless error
AssignValue('amsmath.sty_loaded' => 1);
InputDefinitions('cleveref', type => 'sty', noltxml => 1);
AssignValue('amsmath.sty_loaded' => $amswasloaded);
# Now define it back.
AtBeginDocument(sub {
    Let(T_CS('\label'), T_CS('\lx@cleverref@label')); });

# And now we just need to make sure we use the right conjunctions and type names!

# There are 4 ways that a type can be printed:
#  (singular|plural) & (regular|captialized)
# show pattern is creftype(|plural)(|cap)
# In principle, when dealing with multiple refs,
# the types could be different.
# TODO: We're going to pretend that doesn't happen ...

# First attemp
sub splitLabels {
  my ($labels) = @_;
##  return map { CleanLabel($_); } split(/\s*,\s*/, ToString($labels)); }
  return split(/\s*,\s*/, ToString($labels)); }

sub crefMulti {
  my ($labels, $showtype, $capitalized) = @_;
  my @labels = splitLabels($labels);
  if (scalar(@labels) < 2) {
    return Invocation(T_CS('\lx@cref'),
      T_OTHER($showtype
        ? ($capitalized
          ? "creftypecap~refnum"
          : "creftype~refnum")
        : "refnum"),
      $labels[0]); }
  else {
    my @tokens = (Invocation(T_CS('\lx@cref'),
        T_OTHER($showtype
          ? ($capitalized
            ? "creftypepluralcap~refnum"
            : "creftypeplural~refnum")
          : "refnum"),
        shift(@labels)));
    if (scalar(@labels == 1)) {
      push(@tokens, T_CS('\crefpairconjunction'),
        Invocation(T_CS('\lx@cref'), T_OTHER('refnum'), $labels[0])); }
    else {
      while (scalar(@labels) > 1) {
        push(@tokens, T_CS('\crefmiddleconjunction'),
          Invocation(T_CS('\lx@cref'), T_OTHER('refnum'), shift(@labels))); }
      push(@tokens, T_CS('\creflastconjunction'),
        Invocation(T_CS('\lx@cref'), T_OTHER('refnum'), shift(@labels))); }
    return @tokens; } }
# Since we're not grouping by type, we're ignoring \crefpairgroupconjunction, etc

DefConstructor('\lx@cref {} Semiverbatim',
  "<ltx:ref labelref='#label' show='#1' _force_font='true'/>",
  properties => sub { (label => CleanLabel($_[2])); });

DefMacro('\cref OptionalMatch:* Semiverbatim', sub { crefMulti($_[2], 1, 0); });
DefMacro('\Cref OptionalMatch:* Semiverbatim', sub { crefMulti($_[2], 1, 1); });

DefMacro('\crefrange OptionalMatch:* Semiverbatim Semiverbatim',
  '\lx@cref{creftypeplural~refnum}{#2}\crefrangeconjunction\ref{#3}');
DefMacro('\Crefrange OptionalMatch:* Semiverbatim Semiverbatim',
  '\lx@cref{creftypepluralcap~refnum}{#2}\crefrangeconjunction\ref{#3}');

# Make page refs same as regular?
DefMacro('\cpageref OptionalMatch:* Semiverbatim', sub { crefMulti($_[2], 1, 0); });
DefMacro('\Cpageref OptionalMatch:* Semiverbatim', sub { crefMulti($_[2], 1, 1); });

# More likely with page ranges that the types are different?
DefMacro('\cpagerefrange OptionalMatch:* Semiverbatim Semiverbatim',
  '\lx@cref{creftype~refnum}{#2}\crefrangeconjunction\lx@cref{creftype~refnum}{#3}');
DefMacro('\Cpagerefrange OptionalMatch:* Semiverbatim Semiverbatim',
  '\lx@cref{creftypecap~refnum}{#2}\crefrangeconjunction\lx@ref{creftype~refnum{#3}');

DefMacro('\namecref Semiverbatim',    '\lx@cref{creftype}{#1}');
DefMacro('\nameCref Semiverbatim',    '\lx@cref{creftypecap}{#1}');
DefMacro('\namecrefs Semiverbatim',   '\lx@cref{creftypeplural}{#1}');
DefMacro('\nameCrefs Semiverbatim',   '\lx@cref{creftypepluralcap}{#1}');
DefMacro('\lcnamecref Semiverbatim',  '\lx@cref{creftype}{#1}');
DefMacro('\lcnamecrefs Semiverbatim', '\lx@cref{creftypeplural}{#1}');

DefMacro('\labelcref Semiverbatim',     sub { crefMulti($_[1], 0, 0); });
DefMacro('\labelcpageref Semiverbatim', sub { crefMulti($_[1], 0, 0); });

# No, this isn't quite the same thing...
DefPrimitive('\crefalias {}{}', sub {
    my ($stomach, $counter, $type) = @_;
###    AssignMapping('counter_for_type', ToString($counter) => ToString($type));
    return; });

#======================================================================
#  So for each role=creftype(|plural)(|cap) the macro producing the name should be
# \(cref|Cref)@<type>@name(|@plural)
sub crefType {
  my $type = ToString($_[0]);
  my $acs  = T_CS('\cref@' . $type . '@alias');
  return (LookupDefinition($acs) ? ToString(Expand($acs)) : $type); }

DefMacro('\lx@cleverrefnum@@{}', sub {
    my $cs = T_CS('\cref@' . crefType($_[1]) . '@name');
    return Tokens((LookupDefinition($cs) ? $cs : ())); });
DefMacro('\lx@cleverrefnumplural@@{}', sub {
    my $cs = T_CS('\cref@' . crefType($_[1]) . '@name@plural');
    return Tokens((LookupDefinition($cs) ? $cs : ())); });
DefMacro('\lx@cleverrefnumcap@@{}', sub {
    my $cs = T_CS('\Cref@' . crefType($_[1]) . '@name');
    return Tokens((LookupDefinition($cs) ? $cs : ())); });
DefMacro('\lx@cleverrefnumpluralcap@@{}', sub {
    my $cs = T_CS('\Cref@' . crefType($_[1]) . '@name@plural');
    return Tokens((LookupDefinition($cs) ? $cs : ())); });

AssignMapping('type_tag_formatter', 'creftype'          => '\lx@cleverrefnum@@');
AssignMapping('type_tag_formatter', 'creftypeplural'    => '\lx@cleverrefnumplural@@');
AssignMapping('type_tag_formatter', 'creftypecap'       => '\lx@cleverrefnumcap@@');
AssignMapping('type_tag_formatter', 'creftypepluralcap' => '\lx@cleverrefnumpluralcap@@');

#======================================================================
1;
